// Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <math.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <linux/input.h>

#include "touch_noise_filter/touch_noise_filter.h"

void TouchNoiseFilterLog(int verb, const char* format, ...) {
  va_list args;
  va_start(args, format);
  vprintf(format, args);
  va_end(args);
}

__attribute__((noreturn))  // to appease g++
void usage(const char* argv0) {
  printf("Usage: %s logfile\n", argv0);
  exit(1);
}

#define PERROR_ASSERT(x, str)                   \
  do {                                          \
    bool success = (x);                         \
    if (!success) {                             \
      perror(str);                              \
      exit(1);                                  \
    }                                           \
  } while (0);

struct timeval TimevalFromDouble(double when) {
  long int_part = static_cast<long>(when);
  long micro_part = static_cast<long>(static_cast<double>(1000000.0) *
                                      fmod(when, 1.0) + 0.5);
  struct timeval tv = { int_part, micro_part };
  return tv;
}

void ParseLine(const char* line, void* x_filter) {
  const char kPrefix[] = "E: ";
  if (strncmp(line, kPrefix, strlen(kPrefix)))
    return;  // doesn't have prefix
  
  double when;
  int type;
  int code;
  int value;
  
  PERROR_ASSERT(
      sscanf(line, "E: %lf %x %x %d", &when, &type, &code, &value) == 4,
      "sscanf");

  struct input_event ev = {
    TimevalFromDouble(when),
    static_cast<__u16>(type),
    static_cast<__u16>(code),
    static_cast<__s32>(value)
  };
  XFilterHandleInputEvent(x_filter, &ev);
  if (type == 0 && code == 0 && value == 0) {
    uint64_t canceled = 0;
    XFilterGetCanceledTouches(x_filter, &canceled);
    if (canceled) {
      printf("CANCELED SLOTS: ");
      for (size_t i = 0; i < 8 * sizeof(canceled); i++) {
        if (!(canceled & (1ULL << i)))
          continue;
        printf("%zu ", i);
      }
      printf("\n");
    }
  }
  // printf("GOT LINE: %f (%ld . %ld)%x %x %d\n", when * 10000,
  //        ev.time.tv_sec, ev.time.tv_usec,
  //        type, code, value);
}

int main(int argc, char** argv) {
  if (argc < 2)
    usage(argv[0]);
  const char* filename = argv[1];
  
  void* x_filter = NewXFilter();
  
  FILE* fp = fopen(filename, "r");
  PERROR_ASSERT(fp, "fopen");
  while (true) {
    char buf[1024];
    char* result = fgets(buf, sizeof(buf), fp);
    if (result == NULL)
      break;
    ParseLine(buf, x_filter);
  }
  fclose(fp);
  
  FreeXFilter(x_filter);
}
